package com.maxie.group;

import com.maxie.lang.Collection;
import com.maxie.lang.Iterator;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * 按照自己的遍历逻辑重写迭代器
 */

public class GroupStructure implements Collection<Employee, Link> {

    private final Logger logger = LoggerFactory.getLogger(GroupStructure.class);

    /**
     * 组织链的名称
     */
    private String groupName;


    /**
     * 组织链的头部 （整个组织的根节点）
     */
    private Integer groupId;


    private Map<Integer, List<Link>> linksMap = new HashMap<>();

    private Map<Integer, Employee> employees = new HashMap<>();

    private Map<Integer, Integer> reversedLinks = new HashMap<>();

    public GroupStructure(String groupName, Integer groupId) {
        this.groupName = groupName;
        this.groupId = groupId;
    }

    @Override
    public boolean add(Employee employee) {
        // add
        // update
        return null != employees.put(employee.getuId(), employee);
    }

    @Override
    public boolean remove(Employee employee) {
        if (Objects.isNull(employees.get(employee.getuId()))) {
            logger.warn("没有该元素，无需删除");
            return false;
        } else {
            employees.remove(employee.getuId());
            return true;
        }
    }

    @Override
    public boolean addLink(Link link) {
        Integer fromId = link.getFromId();
        buildReversedLinks(link);

        if (Objects.isNull(linksMap.get(fromId))) {
            ArrayList<Link> links = new ArrayList<>();
            links.add(link);
            linksMap.put(fromId, links);
        } else {
            List<Link> links = linksMap.get(fromId);
            // 判重
            if (links.contains(link)) {
                logger.warn("该关系已存在");
                return false;
            } else {
                links.add(link);
                linksMap.put(fromId, links);
            }
        }
        return true;
    }

    /**
     * 构建反转关系
     *
     * @param link
     */
    private void buildReversedLinks(Link link) {
        // 维护反转关系
        if (Objects.isNull(reversedLinks.get(link.getToId()))) {
            reversedLinks.put(link.getToId(), link.getFromId());
        } else {
            logger.warn("该关系已存在");
        }
    }

    @Override
    public boolean removeLink(Link link) {
        if (Objects.isNull(linksMap.get(link.getFromId()))) {
            logger.warn("不存在这个link");
            return false;
        } else {
            linksMap.get(link.getFromId()).remove(link);
            return true;
        }
    }

    @Override
    public Iterator<Employee> iterator() {
        return new Iterator<Employee>() {
            private int totalSize = 0; // 总数
            private int fromId = groupId; // 起始
            private int toId = groupId; // 结束

            // key:父节点  value:子节点已经遍历的个数
            Map<Integer, Integer> cursor = new HashMap<>();
            @Override
            public boolean hasNext() {
                return totalSize < employees.size();
            }

            @Override
            public Employee next() {
                // 开始遍历
                List<Link> links = linksMap.get(toId);
                // 即使是叶子节点，也需要去cursor中维护自己：(key,0)
                int cursorIdx = getCursorIdx(toId);

                // 同级节点扫描
                if (null ==  links) {
                    // 这是叶子节点：需要找父节点fromId，然后找父节点的子节点
                    cursorIdx = getCursorIdx(fromId);
                    // 获取父节点的所有link
                    links = linksMap.get(fromId);
                }

                // 终止条件：父级节点扫描
                if (cursorIdx > links.size() -1) {
                    // 获取父节点fromId的父级节点fromId
                    fromId = reversedLinks.get(fromId);
                    // 维护计数
                    cursorIdx = getCursorIdx(fromId);
                    links = linksMap.get(fromId);

                }

                // 处理当前节点
                Link link = links.get(cursorIdx);
                toId = link.getToId();
                fromId = reversedLinks.get(toId);
                totalSize++;
                return employees.get(toId);
            }


            private int getCursorIdx(int key) {
                int countIndex = 0;
                if (Objects.isNull(cursor.get( key))) {
                    cursor.put(key, countIndex);
                } else {
                    countIndex = cursor.get(key) + 1;
                    cursor.put(key, countIndex);
                }
                return countIndex;
            }
        };
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Integer getGroupId() {
        return groupId;
    }

    public void setGroupId(Integer groupId) {
        this.groupId = groupId;
    }
}
